import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { JwtService } from "@nestjs/jwt";
import { Request } from 'express'
import { TOKEN_SECRET_KEY } from "src/constant/provider.const";
import { IS_PUBLIC_KEY } from "src/decorators/is-public.decorator";

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
        private readonly jwtService: JwtService,
        private reflector: Reflector,
        @Inject(TOKEN_SECRET_KEY) private tokenSecret: string, // 在 auth.module 中获取并注册了 TOKEN_SECRET_KEY 为 其他 Service所用
    ) { }
    async canActivate(context: ExecutionContext): Promise<boolean> {
        // Handle public routes. --- start
        const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
            context.getHandler(),
            context.getClass(),
        ]);
        if (isPublic) {
            return true;
        }
        // Handle public routes. --- end

        const request = context.switchToHttp().getRequest();
        const token = this.extractTokenFromHeader(request);
        // no token, throw error
        if (!token) {
            throw new UnauthorizedException();
        }

        // verify token
        try {
            const payload = await this.jwtService.verifyAsync(token, { secret: this.tokenSecret, });
            // We're assigning the payload to the request object here
            // so that we can access it in our route handlers
            request["user"] = payload;
        } catch (error) {
            throw new UnauthorizedException();
        }
        return true;
    }

    private extractTokenFromHeader(request: Request): string | undefined {
        const [type, token] = request.headers.authorization?.split(" ") ?? [];
        return type === "Bearer" ? token : undefined;
    }
}